package com.wn.budget.code.context;

import com.wn.budget.model.Admin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Optional;

/**
 * 上下文状态管理器
 * <p>
 * 职责：
 * 在AccessSessionInitializeFilter中将Session中上下文状态关联至当前请求处理线程的ThreadLocalMap中
 * 统一管理并方便后续对上下文状态的读写，避免以Map的方式直接访问HttpSession对象
 *
 * @author zhouzhiming@ygsoft.com
 */
public class ContextManager {

    private static final Logger log = LoggerFactory.getLogger(ContextManager.class);

    private static final ThreadLocal<HttpSession> contextMap = new ThreadLocal<>();

    /**
     * Session中上下文状态对象的Key值
     */
    private static final String CONTEXT_KEY = "LOGIN_USER";

    private static final String LOG4J_MDC_KEY = "user";

    /**
     * 不允许外部创建上下文管理器
     */
    private ContextManager() {
    }

    /**
     * 获取当前登录用户的上下文数据，如果当前Session中没有上下文数据，则会返回一个新的Context对象
     */
    public static Context getCurrentContext() {
        return Optional.ofNullable(contextMap.get()).map(u -> (Context) u.getAttribute(CONTEXT_KEY)).orElse(new Context());
    }

    /**
     * 此动作应由每次请求时初始化至当前请求的线程上下文之中
     */
    public static void initSession(final HttpServletRequest request) {
        HttpSession session = request.getSession();
        contextMap.set(session);
        Context context = (Context) session.getAttribute(CONTEXT_KEY);
        if (context == null) {
            context = new Context();
            context.setCreateTime(session.getCreationTime());
            context.setSessionID(session.getId());
            context.setClientIP(request.getRemoteAddr());
            session.setAttribute(CONTEXT_KEY, context);
            MDC.clear();
            log.trace("当前Session中未包含任何上下文信息");
        } else {
            log.trace("当前Session的信息为：\n{}", context);
            // 设置Log4j MDC
            if (context.getLoginUser() != null) {
                MDC.put(LOG4J_MDC_KEY, context.getLoginUser().account + "@");
            } else {
                MDC.clear();
            }
        }
        context.setLastAccessedTime(session.getLastAccessedTime());
        context.setRequestURI(request.getRequestURI());
        log.debug("绑定上下文状态至请求: {} -> {}", context.getClientIP(), context.getRequestURI());
    }

    public static void setLoginUser(final HttpServletRequest request, Admin admin) {
        HttpSession session = request.getSession(true);
        session.setAttribute("LOGIN_USER", admin);
    }

    public static Admin getLoginUser(final HttpServletRequest request) {
        HttpSession session = request.getSession(true);
        Admin admin = (Admin) session.getAttribute("LOGIN_USER");
        if (admin == null)
            throw new RuntimeException("请登录");
        return admin;
    }

    public static boolean logout(final HttpServletRequest request){
        HttpSession session = request.getSession(true);
        session.removeAttribute("LOGIN_USER");
        return true;
    }
}
